package com.huanglejing.shanggou.http


import com.google.gson.Gson
import com.google.gson.JsonObject
import com.google.gson.TypeAdapter
import com.google.gson.reflect.TypeToken
import com.huanglejing.mylibrary.KLog
import com.huanglejing.shanggou.R
import com.huanglejing.shanggou.common.AppContext
import com.huanglejing.shanggou.exception.APIException
import com.huanglejing.shanggou.exception.JOSNEmptyException
import com.huanglejing.shanggou.exception.JsonParseException
import com.huanglejing.shanggou.exception.TokenExpireException
import com.huanglejing.shanggou.utils.ToastUtils
import com.huanglejing.shanggou.utils.checkEmpty
import com.huanglejing.shanggou.utils.tojsonString
import okhttp3.MediaType
import okhttp3.RequestBody
import okhttp3.ResponseBody
import okhttp3.internal.Util.UTF_8
import okio.Buffer
import retrofit2.Converter
import retrofit2.Retrofit
import java.io.IOException
import java.io.OutputStreamWriter
import java.lang.reflect.Type


/**
 * Created by 75176 on 2016/7/24 0024.
 * 自定义返回值解析器
 */
class DADIGsonConverter : Converter.Factory() {

//    private val MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8")
//    private val UTF_8 = Charset.forName("UTF-8")


    override fun requestBodyConverter(type: Type, parameterAnnotations: Array<Annotation>?, methodAnnotations: Array<Annotation>?, retrofit: Retrofit?): Converter<*, RequestBody>
            = RequestConverterFactory(AppContext.gson(), AppContext.gson().getAdapter(TypeToken.get(type)), parameterAnnotations, methodAnnotations, retrofit)


    override fun responseBodyConverter(type: Type, annotations: Array<Annotation>?, retrofit: Retrofit?): Converter<ResponseBody, *> = ResponseConverterFactory<Any>(AppContext.gson(), type)

    internal inner class ResponseConverterFactory<T>(private val gson: Gson, private val type: Type) : Converter<ResponseBody, T> {
        @Throws(IOException::class)
        override fun convert(value: ResponseBody): T {

            val resVal = value.string()
            val json = try {
                KLog.d("convert : res value : $resVal")
                gson.fromJson(resVal, JsonObject::class.java)
            } catch (e: Exception) {
                //session 过期
                throw JsonParseException()
            }

            KLog.w("Network", "response>> $resVal")
            //ResultResponse 只解析result字段
            if (json == null || json.isJsonNull || json.entrySet().isEmpty()) {
                throw JOSNEmptyException()
            }
            val res = json.get("status")?.asString?.toLowerCase()?.trim()
            if ("00".equals(res)) {


            }else{
                //失败
                val errorMsg = json.get("message")?.asString
                val code = (json.get("messageCode")?.asString ?: "").toIntOrNull()
                if (errorMsg.checkEmpty()) throw APIException("${AppContext.get().resources.getString(R.string.str_error_no_msg)}. code = $code")
                if (errorMsg?.contains("token校验失败") == true) {
                    ToastUtils.toastLong(AppContext.get().resources.getString(R.string.str_expire_relogin))
                }
                when (code) {

                    null -> throw APIException(errorMsg ?: AppContext.get().resources.getString(R.string.str_unknown_error))
                    9999 -> throw TokenExpireException(errorMsg ?: AppContext.get().resources.getString(R.string.str_unknown_error), code)
                    else -> throw APIException(errorMsg ?: AppContext.get().resources.getString(R.string.str_error), code)
                }
            }
            if (JsonObject::class.java == getRawClass(type)) { //避免两次的反序列化
                return json as T
            } else {
                return gson.fromJson(json, type)
            }

        }
    }

    private inner class RequestConverterFactory<T>(private val gson: Gson, private val typeAdapter: TypeAdapter<T>, private val paramAnnotations: Array<Annotation>?, private val methodAnnotations: Array<Annotation>?, private val retrofit: Retrofit?) : Converter<T, RequestBody> {
        @Throws(IOException::class)
        override fun convert(value: T): RequestBody {
            KLog.d("RequestBody = ${value.tojsonString()} , typeAdapter = $typeAdapter  ,paramAnnotations =$paramAnnotations , methodAnnotations = $methodAnnotations ,retrofit = $retrofit")
            val buffer = Buffer()
            val writer = OutputStreamWriter(buffer.outputStream(), UTF_8)
            gson.newJsonWriter(writer).use {
                typeAdapter.write(it, value)
            }
            return RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=UTF-8"), buffer.readByteString())
        }
    }

    companion object {
        val mappingMap by lazy { android.support.v4.util.ArrayMap<Type, Class<*>?>() }
        fun getRawClass(type: Type) = mappingMap[type] ?: doGet(type) //避免多次生成TypeToken对象
        fun doGet(type: Type): Class<out Any?> = TypeToken.get(type).rawType!!.apply {
            mappingMap.put(type, this)
        }
    }

}
